package org.jin.jinaicode.controller;

import cn.hutool.json.JSONUtil;
import com.mybatisflex.core.paginate.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.jin.jinaicode.common.BaseResponse;
import org.jin.jinaicode.common.DeleteRequest;
import org.jin.jinaicode.common.ResultUtils;
import org.jin.jinaicode.exception.BusinessException;
import org.jin.jinaicode.exception.ErrorCode;
import org.jin.jinaicode.exception.ThrowUtils;
import org.jin.jinaicode.model.dto.user.AppAddDTO;
import org.jin.jinaicode.model.dto.user.AppDeployDTO;
import org.jin.jinaicode.model.dto.user.AppQueryDTO;
import org.jin.jinaicode.model.dto.user.AppUpdateDTO;
import org.jin.jinaicode.model.entity.User;
import org.jin.jinaicode.model.vo.AppVO;
import org.jin.jinaicode.service.AppService;
import org.jin.jinaicode.service.UserService;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Map;
import org.jin.jinaicode.model.dto.user.AppPublicDTO;

/**
 * 应用 控制层。
 *
 * @author 小堇
 */
@RestController
@RequestMapping("/app")
@Slf4j
@Tag(name = "应用接口")
public class AppController {

    @Resource
    private AppService appService;

    @Resource
    private UserService userService;

    /**
     * 创建应用
     */
    @PostMapping("/add")
    @Operation(summary = "创建应用", description = "用户创建应用（只需提供提示词，应用名称自动生成，类型默认为多文件模式）")
    public BaseResponse<Long> addApp(@RequestBody AppAddDTO appAddDTO, HttpServletRequest request) {
        if (appAddDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.addApp(appAddDTO, request);
    }

    /**
     * 根据 id 修改自己的应用
     */
    @PostMapping("/update")
    @Operation(summary = "更新应用", description = "用户根据 id 修改自己的应用（支持修改应用名称和封面）")
    public BaseResponse<Boolean> updateApp(@RequestBody AppUpdateDTO appUpdateDTO, HttpServletRequest request) {
        if (appUpdateDTO == null || appUpdateDTO.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.updateApp(appUpdateDTO, request);
    }

    /**
     * 更新应用公开状态
     */
    @PostMapping("/update/public")
    @Operation(summary = "更新应用公开状态", description = "用户更新自己应用的公开状态（1-公开，0-私有）")
    public BaseResponse<Boolean> updateAppPublicStatus(@RequestBody AppPublicDTO appPublicDTO, HttpServletRequest request) {
        if (appPublicDTO == null || appPublicDTO.getAppId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.updateAppPublicStatus(appPublicDTO, request);
    }

    /**
     * 根据 id 删除自己的应用
     */
    @PostMapping("/delete")
    @Operation(summary = "删除应用", description = "用户根据 id 删除自己的应用")
    public BaseResponse<Boolean> deleteApp(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.deleteApp(deleteRequest, request);
    }

    /**
     * 根据 id 查看应用详情
     */
    @GetMapping("/getById")
    @Operation(summary = "获取应用详情", description = "用户根据 id 查看应用详情")
    public BaseResponse<AppVO> getAppById(@RequestParam("id") long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "ID不合法");
        }
        return appService.getAppById(id, request);
    }

    /**
     * 分页查询自己的应用列表
     */
    @PostMapping("/list/my")
    @Operation(summary = "分页查询自己的应用", description = "用户分页查询自己的应用列表")
    public BaseResponse<Page<AppVO>> listMyAppByPage(@RequestBody AppQueryDTO appQueryDTO, HttpServletRequest request) {
        if (appQueryDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.listMyAppByPage(appQueryDTO, request);
    }

    /**
     * 分页查询精选的应用列表
     */
    @PostMapping("/list/featured")
    @Operation(summary = "分页查询精选应用", description = "用户分页查询精选的应用列表")
    public BaseResponse<Page<AppVO>> listFeaturedAppByPage(@RequestBody AppQueryDTO appQueryDTO,
                                                           HttpServletRequest request) {
        if (appQueryDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.listFeaturedAppByPage(appQueryDTO, request);
    }

    /**
     * 分页查询所有精选应用列表（公开接口）
     */
    @PostMapping("/list/featured/all")
    @Operation(summary = "分页查询所有精选应用", description = "分页查询所有精选应用列表（无需登录）")
    public BaseResponse<Page<AppVO>> listAllFeaturedAppByPage(@RequestBody AppQueryDTO appQueryDTO) {
        if (appQueryDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.listAllFeaturedAppByPage(appQueryDTO);
    }

    /**
     * 分页查询公开应用列表（公开接口）
     */
    @PostMapping("/list/public")
    @Operation(summary = "分页查询公开应用", description = "分页查询公开应用列表（无需登录）")
    public BaseResponse<Page<AppVO>> listPublicAppByPage(@RequestBody AppQueryDTO appQueryDTO) {
        if (appQueryDTO == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        return appService.listPublicAppByPage(appQueryDTO);
    }

    /**
     * 流式生成代码SSE
     */
    @GetMapping(value = "/chat/gen/code", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @Operation(summary = "流式生成代码", description = "用户根据 id 流式生成代码")
    public Flux<ServerSentEvent<String>> chatToGenCode(@RequestParam("appId") Long appId, @RequestParam("userMessage") String userMessage,
                                                       HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "请先登录");
        }
        if (appId == null || appId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "ID不合法");
        }
        if (userMessage == null || userMessage.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "提示词不能为空");
        }
        Flux<String> stringFlux = appService.chatToGenCode(appId, userMessage, loginUser);
        return stringFlux.map(chunk -> {
                    Map<String, String> wrapper = Map.of("d", chunk);
                    String jsonStr = JSONUtil.toJsonStr(wrapper);
                    return ServerSentEvent.<String>builder()
                            .data(jsonStr)
                            .build();
                })
                .concatWith(Mono.just(
                        //发送结束时间
                        ServerSentEvent.<String>builder()
                                .event("done")
                                .data("")
                                .build()
                ));
    }

    /**
     * 应用部署
     *
     * @param appDeployRequest 部署请求
     * @param request          请求
     * @return 部署 URL
     */
    @PostMapping("/deploy")
    public BaseResponse<String> deployApp(@RequestBody AppDeployDTO appDeployRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appDeployRequest == null, ErrorCode.PARAMS_ERROR);
        Long appId = appDeployRequest.getAppId();
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用 ID 不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 调用服务部署应用
        String deployUrl = appService.deployApp(appId, loginUser);
        return ResultUtils.success(deployUrl);
    }

}
